//
// Created by wxd on 2025/6/29.
//

#include "Logger.h"


#include <iostream>
#include <cstring>
#include <sstream>
#include <chrono>
#include <ctime>
#include <thread>
#include <unordered_map>

// 实例化
Logger& Logger::getInstance() {
    static Logger instance;
    return instance;
}

Logger::Logger() : m_Level(LogLevel::INFO), m_ConsoleOutput(true), m_Initialized(false), m_FileOutput(false) {}

Logger::~Logger() {
    if (m_FileStream.is_open()) {
        m_FileStream.close();
    }
}

// 初始化
void Logger::init(LogLevel level, const std::string &fileName, bool consoleOutput, bool fileOutput) {
    std::lock_guard<std::mutex> lock(m_Mutex);

    if (m_Initialized) {
        return;
    }

    m_Level = level;
    m_ConsoleOutput = consoleOutput;
    m_FileOutput = fileOutput;

    if (m_FileOutput && !fileName.empty()) {
        m_FileStream.open(fileName, std::ios::out | std::ios::app);

        if (m_FileStream.is_open()) {
            std::cerr << "Logger::init() - Failed to open file " << fileName << std::endl;
        }
    }

    m_Initialized = true;
}

void Logger::setLevel(LogLevel level) {
    std::lock_guard<std::mutex> lock(m_Mutex);
    m_Level = level;
}

LogLevel Logger::getLevel() const {
    return m_Level;
}

void Logger::log(LogLevel level,
                 const std::string &package,
                 const std::string &currentFile,
                 const std::string &className,
                 const std::string &function,
                 int line,
                 const std::string &message) {

    if (level < m_Level || !m_Initialized) {
        return;
    }

    std::lock_guard<std::mutex> lock(m_Mutex);

    std::ostringstream oss;

    oss << getCurrentTime() << " "
        << "[" << threadId2String() << "] "
        << "[" << logLevel2String(level) << "] "
        << "[" << package << "] ";

    if (!className.empty()) {
        // 简化类名 (去掉可能存在的类型修饰)
        std::string simpleClassName = className;
        size_t spacePos = simpleClassName.find_last_of(' ');
        if (spacePos != std::string::npos) {
            simpleClassName = simpleClassName.substr(spacePos + 1);
        }

        oss << "[" << simpleClassName << "] ";
    }

    oss << "[" << function << ":" << line << "] "
        << "[" << currentFile << "] "
        << message
        << std::endl;

    std::string logEntry = oss.str();

    if (m_ConsoleOutput) {
        if (level >= LogLevel::ERROR) {
            std::cerr << logEntry;
        } else {
            std::cout << logEntry;
        }
    }

    // 写入文件
    if (m_FileStream.is_open()) {
        m_FileStream << logEntry;
        m_FileStream.flush();
    }
}

void Logger::log(LogLevel level,
                 const std::string &package,
                 const std::string &currentFile,
                 const std::string &function,
                 int line,
                 const std::string &message) {

    if (level < m_Level || !m_Initialized) {
        return;
    }

    std::lock_guard<std::mutex> lock(m_Mutex);

    std::ostringstream oss;

    oss << getCurrentTime() << " "
        << "[" << threadId2String() << "] "
        << "[" << logLevel2String(level) << "] "
        << "[" << package << "] ";

    oss << "[" << function << ":" << line << "] "
        << "[" << currentFile << "] "
        << message
        << std::endl;

    std::string logEntry = oss.str();

    if (m_ConsoleOutput) {
        if (level >= LogLevel::ERROR) {
            std::cerr << logEntry;
        } else {
            std::cout << logEntry;
        }
    }

    // 写入文件
    if (m_FileOutput && m_FileStream.is_open()) {
        m_FileStream << logEntry;
        m_FileStream.flush();
    }
}


void Logger::flush() {
    std::lock_guard<std::mutex> lock(m_Mutex);

    if (m_FileStream.is_open()) {
        m_FileStream.flush();
    }
}

// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
std::string Logger::getCurrentTime() const {
    auto now = std::chrono::system_clock::now();
    auto in_time_t = std::chrono::system_clock::to_time_t(now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

    std::stringstream ss;
    ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %H:%M:%S");
    ss << "." << std::setfill('0') << std::setw(3) << ms.count();

    return ss.str();
}

// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
std::string Logger::logLevel2String(LogLevel level) const {
    switch (level) {
        case LogLevel::TRACE:
            return "TRACE";
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::WARN:
            return "WARN";
        case LogLevel::ERROR:
            return "ERROR";
        case LogLevel::FATAL:
            return "FATAL";
        case LogLevel::OFF:
            return "OFF";
        default:
            return "UNKNOWN";
    }
}

// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
std::string Logger::threadId2String() const {
    const auto threadId = std::this_thread::get_id();
    std::ostringstream oss;
    oss << threadId;
    return oss.str();
}

bool Logger::isInitialized() const {
    return m_Initialized.load();
}







